#include "common.h"

#include <assert.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "common_test.h"
#include "util/tick.h"
#include "util/thread.h"
#include <SDL2/SDL.h>
#include <SDL2/SDL_events.h>

#define SDL_THREAD_FINISH (SDL_USEREVENT+1)
#define FINISH_ 30
#define COND_SIGNAL_ 15
#define TIME_WAIT_ 3


SDL_mutex* data_lock;
SDL_cond * cond;

int SDLThread1(void *data)
{
    int* pi = (int*)data;
    for (;;){
        if ((*pi) >= FINISH_)
        {
            SDL_Event event;
            event.type = SDL_THREAD_FINISH;
            SDL_PushEvent(&event);
            break;
        }

        SDL_LockMutex(data_lock);

        assert(COND_SIGNAL_ != *pi);

        (*pi)++;
        
        assert(COND_SIGNAL_+1 != *pi);

        printf("This is SDL Thread1, Current i is [%d]\n", (*pi));
        if ((*pi)==COND_SIGNAL_)
        {
            SDL_CondSignal(cond);
        }
        SDL_UnlockMutex(data_lock);
        SDL_Delay(TIME_WAIT_);
    }
    return 0;
}

int SDLThread2(void *data)
{
    int * pi = (int*)data;
    
    for (;;){
        if ((*pi) >= FINISH_)
        {
            SDL_Event event;
            event.type = SDL_THREAD_FINISH;
            SDL_PushEvent(&event);
            break;
        }

        SDL_LockMutex(data_lock);
        SDL_CondWait(cond, data_lock);

        if((*pi) >= FINISH_){
            // 整个程序结束前又运行到此的情况
            SDL_UnlockMutex(data_lock);
            return 0;
        }

        assert(COND_SIGNAL_ == *pi);

        (*pi)++;
        printf("This is SDL Thread2, Current i is [%d]\n", (*pi));		
        SDL_UnlockMutex(data_lock);		
        SDL_Delay(TIME_WAIT_);
    }
    return 0;
}

static void test_sdl_thread(void)
{
    SDL_Event event;
    SDL_Thread* pthread1;
    SDL_Thread* pthread2;
    int count = 0; 

    SDL_Init(SDL_INIT_EVENTS);

    data_lock = SDL_CreateMutex();
    cond = SDL_CreateCond();

    pthread1 = SDL_CreateThread(SDLThread1, "Thread1", &count);
    pthread2 = SDL_CreateThread(SDLThread2, "Thread2", &count);

    for (;;)
    {
        SDL_WaitEvent(&event);
        if (event.type == SDL_THREAD_FINISH){
            assert(count == FINISH_);
            // 保证线程2能正常结束
            SDL_CondSignal(cond);
            break;
        }
    }
    
    SDL_DestroyCond(cond);
    SDL_DestroyMutex(data_lock);

    SDL_WaitThread(pthread2,NULL);
    SDL_WaitThread(pthread1,NULL);

    SDL_Quit();
}

static void test_sc_mutex_init(void){
    TEST_START_INFO;

    TEST_LINE_REPORT_START;

    sc_mutex mutex;
    assert(!mutex.mutex);
    sc_mutex_init(&mutex);
    assert(mutex.mutex);
#ifndef NDEBUG
    assert(!mutex.locker);
#endif

    /*
    // 下面的写法是断言不成功的,回收了资源，但并没有把这个指针指向NULL
    sc_mutex_destroy(&mutex);
    assert(!mutex.mutex);
    */
    
    TEST_END_INFO;
}

int main(int argc, char *argv[]) {
    (void) argc;
    (void) argv;

    /* 
    
    下面的两个测试单独运行都能成功，放在一起反倒不能运行成功了，TODO 为什么？
    test_sdl_thread() 仅用于调试时演示，不能做为单元测试使用，整体运行单元测试不能通过

    */
    // test_sdl_thread();
    // test_sc_mutex_init();

    return 0;
};